using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Services;
using JigLibX.Physics;
using Utilities;
using SpaceBattle.Logic;
using SpaceBattle.Logic.SampleLevel;


namespace SpaceBattle
{
    using Nuke = Projectile;
    using NukeData = ProjectileData;

    public abstract class ProjectilesLayer : PlayerLayer
    {
        public ProjectilesLayer(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
        }

        protected override void DrawProjectiles(State current_state, float dt)
        {
            DrawProjectiles(current_state.primary_weapons,current_state, dt);
            DrawProjectiles(current_state.secondary_weapons,current_state, dt);
        }
        
        private void DrawProjectiles(ArrayList<Projectile> projectiles, State current_state, float dt)
        {
            //for_each (var shot in current_state.primary_weapons.Concat(current_state.seondary_weapons))
            //{
            for (int i=0; i< projectiles.Count; i++){
                var shot = projectiles[i];
                float angle = (float)Math.Atan2(shot.geometry.Velocity.Z, shot.geometry.Velocity.X);
                var theta = (float)Math.Atan2(shot.geometry.Velocity.X, shot.geometry.Velocity.Z);
                switch (shot.weapon_config.Type)
                {
                    case WeaponType.Machine_Gun:
                        {
                            MachineGunParticle p = new MachineGunParticle() { Self = shot.self };
                            // laser appena creato, inizializziamo i ParticleData corrispondenti
                            if (p.Particle == null)
                            {
#warning Kekko : numeri magici!
                                float Xoffset = rand.Next(-20, 20) / 64.0f;
                                float Zoffset = rand.Next(-20, 20) / 64.0f;
                                shot.geometry.Position = new Vector3(shot.geometry.Position.X + Xoffset, 0.0f, shot.geometry.Position.Z + Zoffset);
                                p.Particle =
                                  effects.AddMachineGunParticle(shot.geometry.Position, Vector3.Zero,
                                  Math.Max(0.05f * shot.size * max_depth / Vector3.Distance(EyePosition, shot.geometry.Position), 1.0f * shot.size),
                                  shot.faction == Faction.Enemy ? Color.White : Color.Yellow, angle + MathHelper.PiOver2);
                            }
                            else
                                p.Particle.Position =
                                    shot.geometry.Transform.Position;
                        }
                        break;
                    case WeaponType.Plasma:
                        {
                            PlasmaParticle p = new PlasmaParticle() { Self = shot.self };

                            // laser appena creato, inizializziamo i ParticleData corrispondenti
                            if (p.Particle == null)
                                p.Particle =
                                  effects.AddPlasmaParticle(shot.geometry.Transform.Position, Vector3.Zero,
                                  Math.Max(0.05f * shot.size * max_depth / Vector3.Distance(EyePosition, shot.geometry.Position), 1.0f * shot.size),
                                  shot.faction == Faction.Enemy ? Color.White : Color.CornflowerBlue);
                            else
                                p.Particle.Position =
                                    shot.geometry.Transform.Position;
                        }
                        break;
                    case WeaponType.Double_Plasma:
                        {
                            DoublePlasmaParticle dp = new DoublePlasmaParticle() { Self = shot.self };
                            //aggiornamento timer
                            var perp = Vector3.Cross(Vector3.Normalize(shot.geometry.Velocity), Vector3.Up);
                            dp.ParticleTimer += dt;

                            // gestione main_particle
                            // laser appena creato, inizializziamo i PlasmaParticleData corrispondenti
                            if (dp.MainParticle == null)
                                dp.MainParticle =
                                  effects.AddPlasmaParticle(shot.geometry.Transform.Position, Vector3.Zero,
                                  Math.Max(0.05f * shot.size * max_depth / Vector3.Distance(EyePosition, shot.geometry.Position), 0.8f * shot.size),
                                  shot.faction == Faction.Enemy ? Color.White : Color.CornflowerBlue);
                            else
                                dp.MainParticle.Position =
                                    shot.geometry.Transform.Position + perp * 2 * shot.size;


                            // gestione secondary_particle
                            if (dp.SecondParticle == null)
                                dp.SecondParticle =
                                  effects.AddPlasmaParticle(shot.geometry.Transform.Position, Vector3.Zero,
                                    Math.Max(0.05f * shot.size * max_depth / Vector3.Distance(EyePosition, shot.geometry.Position), 0.8f * shot.size),
                                    shot.faction == Faction.Enemy ? Color.White : Color.CornflowerBlue);
                            else
                                dp.SecondParticle.Position =
                                    shot.geometry.Transform.Position - perp * 2 * shot.size;
                        }
                        break;
                    case WeaponType.Triple_Plasma:
                        {
                            TriplePlasmaParticle dp = new TriplePlasmaParticle() { Self = shot.self };
                            //aggiornamento timer
                            dp.ParticleTimer += dt / 1.5f;


                            // gestione main_particle
                            // laser appena creato, inizializziamo i PlasmaParticleData corrispondenti
                            if (dp.MainParticle == null)
                            {
                                dp.MainParticle =
                                  effects.AddPlasmaParticle(shot.geometry.Transform.Position, Vector3.Zero,
                                  Math.Max(0.05f * shot.size * max_depth / Vector3.Distance(EyePosition, shot.geometry.Position), 1.2f * shot.size),
                                  shot.faction == Faction.Enemy ? Color.White : Color.CornflowerBlue);
                                dp.ParticleTimer = ((float)rand.NextDouble()) - 0.5f;
                            }
                            else
                                dp.MainParticle.Position =
                                    shot.geometry.Transform.Position;


                            // gestione secondary_particle
                            if (dp.SecondParticle == null)
                            {
                                dp.SecondParticle =
                                  effects.AddPlasmaParticle(shot.geometry.Transform.Position, Vector3.Zero,
                                    Math.Max(0.05f * shot.size * max_depth / Vector3.Distance(EyePosition, shot.geometry.Position), 0.6f * shot.size),
                                    shot.faction == Faction.Enemy ? Color.White : Color.Yellow);
                            }
                            else
                                dp.SecondParticle.Position =
                                    shot.geometry.Transform.Position + new Vector3(3 * shot.size * (float)Math.Cos(20 * dp.ParticleTimer), 0.0f, 2 * shot.size * (float)Math.Sin(16 * dp.ParticleTimer));

                            // gestione third_particle
                            if (dp.ThirdParticle == null)
                            {
                                dp.ThirdParticle =
                                  effects.AddPlasmaParticle(shot.geometry.Transform.Position, Vector3.Zero,
                                    Math.Max(0.05f * shot.size * max_depth / Vector3.Distance(EyePosition, shot.geometry.Position), 0.6f * shot.size),
                                    shot.faction == Faction.Enemy ? Color.White : Color.Yellow);
                            }
                            else
                                dp.ThirdParticle.Position =
                                    shot.geometry.Transform.Position + new Vector3(2 * shot.size * (float)Math.Cos(20 * dp.ParticleTimer + Math.PI), 0.0f, 3 * shot.size * (float)Math.Sin(16 * dp.ParticleTimer + Math.PI));
                        }
                        break;
                    case WeaponType.Laser:
                        LaserParticle llp = new LaserParticle() { Self = shot.self };
                        if (llp.effect == null)
                        {
                            shotinfo = new shot_info()
                            {
                                shot = shot,
                                duration = 0.8f,
                                slow_motion = current_state.slow_motion
                            };
                            llp.effect = effects.AddLaserLine(init_la);
                            //llp.effect = effects.AddLaserLine( l => 
                            //{
                            //    l.Init(shot, 0.3f);
                            //    l.slow_motion = current_state.slow_motion;
                            //});
                        }
                        else
                            llp.effect.slow_motion = current_state.slow_motion;

                        break;
                    //case WeaponType.NonTrackingNuke:
                    //    Nuke.Model.DrawAsBody(Matrix.CreateRotationY(theta + MathHelper.Pi), shot.geometry, view, projection);
                    //    break;
                    case WeaponType.Nuke:
                        //Nuke.Model.DrawAsBody(Matrix.CreateRotationY(theta + MathHelper.Pi), shot.geometry, view, projection);
                        MissileParticle n = new MissileParticle() { Self = shot.self };
                        //if (n.effect == null || n.effect.projectileActive == false)
                        //{
                            shotinfo = new shot_info()
                            {
                                shot = shot,
                                //duration = shot.OwnValue.life,
                                //slow_motion = current_state.slow_motion
                            };
                            n.effect = effects.AddNuke(init_m);
                        //}
                        //else
                            //n.effect.slow_motion = current_state.slow_motion;

                        break;
                    case WeaponType.Smart_Missiles:
                    case WeaponType.Missiles_Swarm:
                        //Swarm.Model.DrawAsBody(Matrix.CreateRotationY(theta + MathHelper.Pi), shot.geometry, view, projection);

                        MissileParticle m = new MissileParticle() { Self = shot.self };
                        //if (m.effect == null || m.effect.projectileActive == false)
                        //{
                            shotinfo = new shot_info()
                            {
                                shot = shot,
                                //duration = shot.OwnValue.life,
                                //slow_motion = current_state.slow_motion
                            };
                            m.effect = effects.AddMissile(init_m);
                        //}
                        //else
                            //m.effect.slow_motion = current_state.slow_motion;

                        break;
                    case WeaponType.Lightning:
                        LightningParticle lp = new LightningParticle() { Self = shot.self };
                        if (lp.effect == null)
                        {
                            shotinfo = new shot_info()
                            {
                                shot = shot,
                                duration = 0.8f,
                                slow_motion = current_state.slow_motion                                
                            };
                            lp.effect = effects.AddThunderbolt(init_li);
                            //lp.effect = effects.AddThunderbolt( t =>
                            //{
                            //    t.Init(shot, 0.8f);
                            //    t.slow_motion = current_state.slow_motion;
                            //});
                        }
                        else
                            lp.effect.slow_motion = current_state.slow_motion;
                        break;
                    case WeaponType.Chain_Reaction:
                        {
                            PlasmaParticle p = new PlasmaParticle() { Self = shot.self };

                            if (p.Particle == null)
                                p.Particle =
                                  //effects.AddPlasmaParticle(shot.geometry.Transform.Position, Vector3.Zero,
                                  effects.AddChainReactionParticle(shot.geometry.Transform.Position, Vector3.Zero,
                                  Math.Max(0.05f * shot.size * max_depth / Vector3.Distance(EyePosition, shot.geometry.Position), 1.0f * shot.size),
                                  Color.White);
                            else
                                p.Particle.Position =
                                    shot.geometry.Transform.Position;
                        }
                        break;
                }
            }
        }

        public struct shot_info
        {
            public Projectile shot;
            public float duration;
            public float slow_motion;
        }
        public static shot_info shotinfo;
        public static Action<SpaceBattle.EffectsManager.LightningEffect> init_li =
            new Action<EffectsManager.LightningEffect>(
            l => {
                l.Init(shotinfo.shot, shotinfo.duration);
                l.slow_motion = shotinfo.slow_motion;            
            });
        public static Action<SpaceBattle.EffectsManager.LaserLineEffect> init_la =
            new Action<EffectsManager.LaserLineEffect>(
            l =>
            {
                l.Init(shotinfo.shot, shotinfo.duration);
                l.slow_motion = shotinfo.slow_motion;
            });
        public static Action<SpaceBattle.EffectsManager.MissileEffect> init_m =
            new Action<EffectsManager.MissileEffect>(
            l =>
            {
                l.Init(shotinfo.shot);//, shotinfo.duration);
                //l.slow_motion = shotinfo.slow_motion;
            });
    }
}
